import os
import json
import time
from pathlib import Path
import joblib
import pandas as pd
import inspect

def save_function_snapshot(func, dir_path, filename='function_snapshot.py'):
    """
    保存一个函数的源代码快照.

    参数:
        func (function): 要保存源代码的函数.
        dir_path (str): 保存快照文件的目录.
        filename (str): 快照文件的名称.

    返回:
        dict: 包含函数名和快照文件路径的元数据.
    """
    snapshot_path = Path(dir_path) / filename
    try:
        source_code = inspect.getsource(func)
        with open(snapshot_path, 'w', encoding='utf-8') as f:
            f.write(f"# Function: {func.__name__}\n")
            f.write("# Source code snapshot saved on: " + time.strftime("%Y-%m-%d %H:%M:%S") + "\n\n")
            f.write(source_code)
        print(f"✓ 函数 '{func.__name__}' 的源代码快照已保存至: {snapshot_path}")
        return {'name': func.__name__, 'snapshot_file': str(snapshot_path)}
    except (TypeError, OSError) as e:
        error_message = f"✗ 无法获取函数 '{func.__name__}' 的源代码: {e}"
        print(error_message)
        return {'name': func.__name__, 'error': error_message}

def setup_experiment_paths(base_dir='experiments', group_name='default_group', experiment_name='default_experiment'):
    """
    创建并返回本次实验所需的所有路径,并处理命名冲突.

    参数:
        base_dir (str): 实验的根目录.
        group_name (str): 组员或小组的名称.
        experiment_name (str): 实验的名称 (例如 'feature_set_v1_lgbm').

    返回:
        dict: 包含所有路径的字典 ('base', 'scaler', 'stats', 'model', 'results').
    """
    # 基础路径
    experiment_base_path = Path(base_dir) / group_name / experiment_name
    
    # 检查路径是否存在,如果存在则添加时间戳来解决冲突
    if experiment_base_path.exists():
        timestamp = time.strftime("%Y%m%d_%H%M%S")
        print(f"警告: 路径 '{experiment_base_path}' 已存在。")
        experiment_base_path = Path(f"{str(experiment_base_path)}_{timestamp}")
        print(f"将使用新路径: '{experiment_base_path}'")

    # 创建目录
    experiment_base_path.mkdir(parents=True, exist_ok=True)
    
    paths = {
        'base': str(experiment_base_path),
        'scaler': str(experiment_base_path / 'scaler.pkl'),
        'stats': str(experiment_base_path / 'stats.pkl'),
        'model': str(experiment_base_path / 'model.pkl'),
        'results': str(experiment_base_path / 'results.json')
    }
    
    print("\n" + "="*50)
    print("实验路径已设置:")
    for key, value in paths.items():
        print(f"- {key.capitalize()} Path: {value}")
    print("="*50 + "\n")

    return paths

def save_object(obj, path):
    """
    使用joblib保存任何Python对象.

    参数:
        obj: 需要保存的对象.
        path (str): 保存路径.
    """
    try:
        joblib.dump(obj, path)
        print(f"✓ 对象已成功保存至: {path}")
    except Exception as e:
        print(f"✗ 保存对象时出错: {e}")

def load_object(path):
    """
    使用joblib加载任何Python对象.

    参数:
        path (str): 加载路径.
    
    返回:
        加载的对象,如果文件不存在则返回None.
    """
    if Path(path).exists():
        try:
            obj = joblib.load(path)
            print(f"✓ 对象已从以下路径加载: {path}")
            return obj
        except Exception as e:
            print(f"✗ 加载对象时出错: {e}")
            return None
    else:
        print(f"✗ 文件未找到: {path}")
        return None

def load_data(train_path='train.csv', test_path=None):
    """
    加载训练和测试数据集.

    参数:
        train_path (str): 训练数据路径.
        test_path (str, optional): 测试数据路径. 默认为None.

    返回:
        pandas.DataFrame or tuple: 如果只提供train_path,则返回训练DataFrame.
                                 如果提供了两个路径,则返回 (train_df, test_df).
    """
    try:
        train_df = pd.read_csv(train_path)
        print(f"✓ 训练数据加载成功: {train_path}, Shape: {train_df.shape}")
    except FileNotFoundError:
        print(f"✗ 错误: 训练文件未找到 '{train_path}'")
        return None

    if test_path:
        try:
            test_df = pd.read_csv(test_path)
            print(f"✓ 测试数据加载成功: {test_path}, Shape: {test_df.shape}")
            return train_df, test_df
        except FileNotFoundError:
            print(f"✗ 错误: 测试文件未找到 '{test_path}'")
            return train_df, None
            
    return train_df

def save_results(results_dict, path):
    """
    将实验结果 (如 AUC, 最佳参数) 保存为JSON文件.

    参数:
        results_dict (dict): 包含结果的字典.
        path (str): 保存JSON文件的路径.
    """
    try:
        with open(path, 'w', encoding='utf-8') as f:
            json.dump(results_dict, f, ensure_ascii=False, indent=4)
        print(f"✓ 实验结果已保存至: {path}")
    except Exception as e:
        print(f"✗ 保存结果时出错: {e}")
